home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / lisp / eulisp / feel-075.lha / feel0.75 / Libs / CSP / csp.em < prev    next >
Lisp/Scheme  |  1992-05-23  |  11KB  |  379 lines

  1. ;; First bash at CSP type language
  2. ;;
  3. ;; need 5 constructs:
  4. ;; while
  5. ;; alt  -- non deterministic selection
  6. ;; par  -- concurrent composition
  7. ;; seq  -- sequential execution (progn may do)
  8. ;; procedures -- creating processes for channels
  9. ;; for: equiv to PAR 
  10. ;; channels -- single-datum things
  11.  
  12. ;; generics 
  13. ;; c-read, c-write, c-ready
  14. ;; connect-processes
  15.  
  16. (defmodule csp 
  17.   (standard0
  18.    semaphores
  19.    loopsII  ;; while
  20.    list-fns) ();; mapvect, collect
  21.  
  22.    ;; Errors
  23.    (print "loading")
  24.   (defcondition CSP-Error () )
  25.   ;; abstract 
  26.   (defstruct Abstract-Channel ()
  27.     ())
  28.   
  29.   ;; define the generics
  30.   ;; for channels
  31.   (defgeneric c-read (channel))
  32.   (defgeneric c-write (channel data))
  33.   (defgeneric c-ready (channel))
  34.  
  35.   ;; for processes
  36.   (defgeneric is-csp-process (thread))
  37.  
  38.   (defgeneric connect-channel-input (channel))
  39.   (defgeneric connect-channel-output (channel))
  40.   ;; should return 'in 'out 'in-out nil
  41.  
  42.   ;; useful...
  43.   (defun make-communication-sem ()
  44.     (let ((sem (make-semaphore)))
  45.       (open-semaphore sem)
  46.       sem))
  47.  
  48.   ;; local channels
  49.   (defstruct Channel Abstract-Channel 
  50.     ((data-ready initform nil accessor Channel-data-ready)
  51.      (in-sem initform (make-communication-sem) 
  52.          accessor Channel-in-sem)
  53.      (out-sem initform (make-communication-sem)
  54.           accessor Channel-out-sem)
  55.      (datum initform '%_Should_not_be_seen_%
  56.         accessor Channel-datum)
  57.      (connected initform nil accessor Channel-connected)
  58.      (input-thread initform nil accessor Channel-input-thread)
  59.      (output-thread initform nil accessor Channel-output-thread))
  60.     constructor make-Channel)
  61.  
  62.   ;; need to watch for tasks finishing 
  63.   (defclass CSP-thread (thread)
  64.     ((parent initform nil accessor CSP-thread-parent))
  65.     metaclass thread-class
  66.     constructor make-CSP-thread)
  67.  
  68.   (print "defined classes")
  69.  
  70.   (defmethod initialize-instance ((proto CSP-thread) lst)
  71.     (let ((new-thread (call-next-method)))
  72.       ((setter CSP-thread-parent) new-thread (current-thread))
  73.       new-thread))
  74.  
  75.   (defmethod c-read ((channel Channel))
  76.     (cond ((not (subthreadp (current-thread) 
  77.                 (Channel-input-thread channel)))
  78.        (error "Read on wrong end: ~a~%" channel))
  79.       (t 
  80.        ((setter Channel-data-ready) channel nil)
  81.        (open-semaphore (Channel-in-sem channel))
  82.        (let ((data (Channel-datum channel)))
  83.          ;; let the other guy out
  84.          ((setter Channel-datum) channel nil)
  85.          (close-semaphore (Channel-out-sem channel))
  86.          (thread-reschedule)
  87.          data))))
  88.  
  89.   (defmethod c-write ((channel Channel) data)
  90.     (cond ((not (subthreadp (current-thread)
  91.                 (Channel-output-thread channel)))
  92.        (error "Write on wrong end: ~a~%" CSP-Error 
  93.           'error-value channel)))
  94.     ((setter Channel-datum) channel data)
  95.     (close-semaphore (Channel-in-sem channel))
  96.     ((setter Channel-data-ready) channel data)
  97.     (open-semaphore (Channel-out-sem channel))
  98.     (thread-reschedule))
  99.  
  100.  
  101.   (defmethod c-ready ((channel Channel))
  102.     (thread-reschedule)
  103.     (Channel-data-ready channel))
  104.    
  105.   (defmethod connect-channel-input ((channel Channel))
  106.     (cond ((Channel-input-thread channel)
  107.        (error "Can't reset channel input\n"
  108.           'error-value channel))
  109.       (t ((setter Channel-input-thread) channel 
  110.           (current-thread))
  111.          channel)))
  112.  
  113.   (defmethod connect-channel-output ((channel Channel))
  114.     (cond ((Channel-output-thread channel)
  115.        (error "Can't reset channel output\n" Internal-Error
  116.           'error-value channel))
  117.       (t ((setter Channel-output-thread) channel
  118.           (current-thread))
  119.          channel)))
  120.  
  121.   (print "and methods")
  122.   ;; channel pairs...
  123.   ;; connections are made with connect-chan-pair
  124.   ;; try u-field first, then l-field
  125.    
  126.   (defstruct Chan-Pair Abstract-Channel
  127.     ((u-chan initform (make-instance Channel) 
  128.          accessor Chan-Pair-u-chan)
  129.      (d-chan initform (make-instance Channel)
  130.          accessor Chan-Pair-d-chan)
  131.      ;; nil 'one 'two
  132.      (connect-count initform nil 
  133.             accessor Chan-Pair-connect-count))
  134.     constructor make-Chan-Pair)
  135.    
  136.   (defconstant *pair-connect-lock* (make-semaphore))
  137.  
  138.   ;; input, output are compulsory...
  139.   (defstruct Connected-Chan-Pair Abstract-Channel
  140.     ((input initarg input 
  141.         accessor Connected-Chan-Pair-input)
  142.      (output initarg output
  143.          accessor Connected-Chan-Pair-output))
  144.     constructor make-Connected-Chan-Pair)
  145.   (print "chans")
  146.   (defmethod initialize-instance ((proto Connected-Chan-Pair) lst)
  147.     (let ((new-obj (call-next-method)))
  148.       (connect-channel-input (Connected-Chan-Pair-input new-obj))
  149.       (connect-channel-output (Connected-Chan-Pair-output new-obj))
  150.       new-obj))
  151.  
  152.   (defun connect-chan-pair (chan-pair)
  153.     (format t "Connect: count: ~a~%"
  154.         (Chan-Pair-connect-count chan-pair))
  155.     (open-semaphore *pair-connect-lock*)
  156.     (cond
  157.      ((not (Chan-Pair-connect-count chan-pair))
  158.       (let ((new-pair (make-Connected-Chan-Pair 
  159.                'input (Chan-Pair-u-chan chan-pair)
  160.                'output (Chan-Pair-d-chan chan-pair))))
  161.     ((setter Chan-Pair-connect-count) chan-pair 'one)
  162.     (close-semaphore *pair-connect-lock*)
  163.     new-pair))
  164.      ((eq (Chan-Pair-connect-count chan-pair) 'one)
  165.       (let ((new-pair (make-Connected-Chan-Pair
  166.                'input (Chan-Pair-d-chan chan-pair)
  167.                'output (Chan-Pair-u-chan chan-pair))))
  168.     ((setter Chan-Pair-connect-count) chan-pair 'two)
  169.     (close-semaphore *pair-connect-lock*)
  170.     new-pair))
  171.      (t (close-semaphore *pair-connect-lock*)
  172.     (error "Tried to connect too often" CSP-Error
  173.            'error-value chan-pair))))
  174.            
  175.   (print "cp")
  176.   ;; methods...
  177.   (defmethod c-read ((cp Connected-Chan-Pair))
  178.     (c-read (Connected-Chan-Pair-input cp)))
  179.  
  180.   (defmethod c-ready ((cp Connected-Chan-Pair))
  181.     (prog1 (c-ready (Connected-Chan-Pair-input cp))
  182.       nil))
  183.     
  184.   (defmethod c-write ((cp Connected-Chan-Pair) data)
  185.     (c-write (Connected-Chan-Pair-output cp) data))
  186.      
  187.   ;; is thread 1 a subthread of thread 2
  188.   (defun subthreadp (thread1 thread2)
  189.     (cond ((eq thread1 thread2) t)
  190.       ((eq (class-of thread1) thread) nil)
  191.       (t (subthreadp (CSP-thread-parent thread1)
  192.              thread2))))
  193.  
  194.   (print "channels")
  195.   ;; 
  196.   ;; Initializing CSP
  197.   
  198.   ;; vectors of channels
  199.   (defun make-channel-vector (n)
  200.     (mapvect make-Channel (make-vector n)))
  201.  
  202.   ;; wait for threads to stop
  203.   (defun await-finish (threads)
  204.     (let ((res (mapcar thread-value threads)))
  205.       res))
  206.  
  207.   (defun make-ready-csp-thread (fn . args)
  208.     (let ((thread  (make-CSP-thread 'function fn)))
  209.       (apply thread-start (cons thread args))
  210.       thread))
  211.    
  212.   ;;
  213.   ;; Non-deterministic alternation:
  214.   ;;  given list of pairs of (chan . result)
  215.   ;; return 1st to be true.
  216.   ;; currently busy-wait
  217.   ;; problem: how to make sure of fairness...
  218.   ;; Non blocking wait should do this (I hope)
  219.   (deflocal *weather* 'sunny)
  220.  
  221.   (defun wait-for-ready-chan (lst)
  222.     (wait-ready-aux (cond ((eq *weather* 'sunny)
  223.                (setq *weather* 'rainy)
  224.                (reverse lst))
  225.               (t (setq *weather* 'sunny)
  226.                  lst))
  227.             nil))
  228.  
  229.   (defun wait-ready-aux (orig-lst lst)
  230.     (cond ((null lst)
  231.        ;;(thread-reschedule)
  232.        (wait-ready-aux orig-lst orig-lst))
  233.       ((c-ready (caar lst))
  234.        ;;(thread-reschedule)
  235.        (cdar lst))
  236.       (t;;(thread-reschedule)
  237.        (wait-ready-aux orig-lst (cdr lst)))))
  238.  
  239.   ;;
  240.   ;; macros
  241.   ;; 
  242.  
  243.   ;; PAR foo bar baz => (await-finish (thread-start (lambda () foo))
  244.   ;;                                  (thread-start (lambda () bar)))
  245.   ;; etc
  246.  
  247.   (defmacro PAR tasks
  248.     `(await-finish (list ,@(mapcar starter tasks))))
  249.   
  250.   
  251.   (defun starter (task)
  252.     `(make-ready-csp-thread (lambda ()  ,task)))
  253.  
  254.   ;; FOR
  255.   ;;
  256.   (defmacro FOR (inits cont-exp increment . body)
  257.     `(let ((@threads@ nil))
  258.        (let (,inits)
  259.      (while ,cont-exp
  260.        (setq @threads@ (cons (make-ready-csp-thread
  261.                   (lambda (,(car inits)) ,@body)
  262.                   ,(car inits))
  263.                  @threads@))
  264.        ,increment))
  265.        (await-finish @threads@)))
  266.  
  267.   ;; MAPPAR (across a list)
  268.   (defun MAPPAR (fn lst)
  269.     (await-finish (mapcar (lambda (obj)
  270.                 (make-ready-csp-thread fn obj))
  271.               lst)))
  272.  
  273.   ;; SEQ (easy)
  274.   (defmacro SEQ jobs
  275.     `(progn ,@jobs))
  276.  
  277.   ;; ALT 
  278.   ;; (ALT ((in chan-1 x)  (j1 j2 j3))
  279.   ;;      ((guard (in chan-2 y)) (a1 a2 a3)))
  280.   ;;
  281.   ;; get-first-ret should return sym to be executed
  282.   ;;
  283.   ;; (let ((continue (get-first-ret (chan 1)
  284.   ;;                                (if guard chan-2 nil))))
  285.   ;;   (cond ((eq continue g1)
  286.   ;;          (let ((x (c-read chan-1)))
  287.   ;;            j1 j2 j3))
  288.   ;;         ((eq continue g2)
  289.   ;;          (let ((y (c-read chan-2)))
  290.   ;;            a1 a2 a3))
  291.   ;;         (t (error "ALT: unexpected return" CSP-Error))))
  292.   (defmacro ALT alternatives
  293.     (let ((named-alternatives (mapcar (lambda (x) (name-alternative x)) alternatives)))
  294.       `(let ((@continue@ (wait-for-ready-chan
  295.               (collect (lambda (x) x)
  296.                    (list ,@(mapcar make-guard
  297.                            named-alternatives))))))
  298.      (cond ,@(append (mapcar make-alt-stmt named-alternatives)
  299.              '((t (cerror "Unexpected return from alt" clock-tick))))))))
  300.  
  301.   ;; should be (sym chan var gaurd-expr junk)
  302.   (defun name-alternative (alternative)
  303.     (let ((guard (car alternative))
  304.       (stmt (cdr alternative)))
  305.       (if (eq (car guard) 'IN)
  306.       (list (gensym) (cadr guard) (caddr guard) t stmt)
  307.     (list (gensym) (cadr (reverse guard))
  308.           (caddr (reverse guard))
  309.           (cddr (reverse guard))
  310.           stmt))))
  311.   
  312.   ;; should be (if (guard) (cons chan sym) nil)
  313.   (defun make-guard (alt)
  314.     `(if ,(cadddr alt) (cons ,(cadr alt) ',(car alt)) nil))
  315.  
  316.   ;; should be ((eq @continue@ sym) (let ((var continue)) junk))
  317.   
  318.   (defun make-alt-stmt (alt)
  319.     `((eq @continue@ ',(car alt)) 
  320.       (let ((,(caddr alt) (c-read ,(cadr alt))))
  321.     ,@(car (last-pair alt)))))
  322.  
  323.   ;; 
  324.   ;; WAIT-FIRST
  325.   ;; like ALT, but taskes list of channels
  326.   ;; (IN-FROM (chan result) lst . cmds)
  327.   (defmacro IN-FROM ( chan-data chans . rest)
  328.     `(let* ((,(car chan-data) (wait-for-ready-chan (mapcar (lambda (x) 
  329.                                  (cons x x))
  330.                                ,chans)))
  331.         (,(cadr chan-data) (IN ,(car chan-data))))
  332.        ,@rest))
  333.   ;; in 
  334.   ;; (in chan var)
  335.  
  336.   (defmacro IN (chan . var)
  337.     (cond (var 
  338.        `(setq ,(car var) (c-read ,chan))(thread-reschedule))
  339.       (t `(c-read ,chan))))
  340.  
  341.   ;; out
  342.   ;; (out char value)
  343.   (defmacro OUT (chan value)
  344.     `(progn (c-write ,chan ,value)(thread-reschedule)))
  345.  
  346.   ;; exports for applications
  347.   
  348.   (export SEQ IN OUT ALT PAR FOR IN-FROM make-Channel make-Chan-Pair connect-channel-output connect-channel-input
  349.       connect-chan-pair)
  350.    
  351.   ;; exports cos of macros
  352.   (export await-finish starter make-ready-csp-thread make-alt-stmt make-guard wait-for-ready-chan 
  353.       c-write c-read c-ready)
  354.   )
  355.  
  356.  
  357. ;; Yet another loop macro (untested by me, but did work once).
  358. (defmodule do
  359.   (standard0)
  360.   ()
  361.  
  362.   (defmacro do (var-init-step-forms end-test-result . body)
  363.     (let ((vars (mapcar car var-init-step-forms))
  364.           (inits (mapcar cadr var-init-step-forms))
  365.           (steps (mapcar caddr var-init-step-forms))
  366.           (end-test (car end-test-result))
  367.           (results (cdr end-test-result)))
  368.     `(let/cc return
  369.        (labels (
  370.          (do-loop ,vars
  371.            (if ,end-test
  372.                (progn ,@results)
  373.                (progn ,@body (do-loop ,@steps)))))
  374.          (do-loop ,@inits)))))
  375.  
  376.   (export do)
  377.  
  378. )
  379.